#include <iostream>
#include <string>

#include "benchmark.hpp"

#include "bs1_benchmark.hpp"
#include "bs2_benchmark.hpp"
#include "evl_benchmark.hpp"
#include "jls_benchmark.hpp"
#include "nss_benchmark.hpp"
#include "sgc_benchmark.hpp"

#include "lib/jl_signal/Signal.h"
#include "lib/jl_signal/StaticSignalConnectionAllocators.h"

/*
g++-4.7 benchmark.cpp jl_signal/ObjectPool.cpp jl_signal/SignalBase.cpp -std=c++11 -O2 -lboost_signals -o ~/benchmark/benchmark.out `pkg-config --cflags --libs sigc++-2.0`
~/benchmark/benchmark.out 8 512 4 > ~/benchmark/dat/out.perf
./bargraph.pl -fig out.perf | fig2dev -L png -m 4 > out.png
*/

int main(int argc, char* argv[])
{
    using namespace benchmark_class;

    using std::cout;
    using std::endl;

    if (argc == 4)
    {
        std::cerr << "[paused] sudo renice -1 `pidof benchmark.out`" << endl;
        char c = std::cin.get(); (void)c;

        jl::StaticSignalConnectionAllocator<c_max_con> signal_con_allocator;
        jl::StaticObserverConnectionAllocator<c_max_con> observer_con_allocator;
        jl::SignalBase::SetCommonConnectionAllocator(&signal_con_allocator);
        jl::SignalObserver::SetCommonConnectionAllocator(&observer_con_allocator);

        Rng_t rng;
        Eng_t eng (0, 100);

        std::size_t ratios[] = { 75, 50, 25 };

        std::size_t start_n = round_2_down(std::stoll(argv[1]));
        std::size_t maximum_n = round_2_up(std::stoll(argv[2]));
        std::size_t timer_limit = Timer_u(Limit_u(std::stoll(argv[1]))).count();

        cout << "=stackcluster;";
        for (auto R : ratios)
        {
            cout << std::to_string(R) << "% ;";
        }
        cout << "\n=sortbmarks";
        cout << "\n=noupperright";
        cout << "\nlegendx=center";
        cout << "\nlegendy=top";
        cout << "\nylabel=Relative Performance" << endl;
        cout << "\n=table";

        for (std::size_t N = start_n; N <= maximum_n; N *= 2)
        {
            cout << endl << "multimulti=" << N << endl << "bs1    ";
            for (auto R : ratios)
            {
                cout << N / Bs1::runtime(rng, eng, N, R, timer_limit) << "    ";
            }
            cout << endl << "bs2    ";
            for (auto R : ratios)
            {
                cout << N / Bs2::runtime(rng, eng, N, R, timer_limit) << "    ";
            }
            cout << endl << "evl    ";
            for (auto R : ratios)
            {
                cout << N / Evl::runtime(rng, eng, N, R, timer_limit) << "    ";
            }
            cout << endl << "jls    ";
            for (auto R : ratios)
            {
                cout << N / Jls::runtime(rng, eng, N, R, timer_limit) << "    ";
            }
            cout << endl << "nss    ";
            for (auto R : ratios)
            {
                cout << N / Nss::runtime(rng, eng, N, R, timer_limit) << "    ";
            }
            cout << endl << "sgc    ";
            for (auto R : ratios)
            {
                cout << N / Sgc::runtime(rng, eng, N, R, timer_limit) << "    ";
            }
        }
    }
    else
    {
        std::cerr << "(start) (end) (timer limit)" << endl;
        return 1;
    }
}
